using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Windows.Forms;

namespace SBS_Map_Editor.MapClasses
{
    public class Map
    {
        #region Variables
        SegmentDefinition[] segDef;
        MapSegment[,] mapSeg;
        Ledge[] ledge;

        public String[] scripts = new String[128];

        int[,] col;
        private string path;

        //public static bool FirstRun { get; set; }
        #endregion

        #region Properties
        public SegmentDefinition[] SegementDefinitions
        {
            get { return segDef; }
        }

        public MapSegment[,] Segments
        {
            get { return mapSeg; }
        }

        public int[,] Grid
        {
            get { return col; }
        }

        public Ledge[] Ledges
        {
            get { return ledge; }
        }

        public string Path
        {
            get { return path; }
            set { path = value; }
        }
        #endregion

        #region Constructor
        public Map()
        {
            for (int i = 0; i < scripts.Length; i++)
                scripts[i] = "";
            ledge = new Ledge[16];
            for (int i = 0; i < 16; i++)
                ledge[i] = new Ledge();

            segDef = new SegmentDefinition[512];
            mapSeg = new MapSegment[3, 64];
            col = new int[20, 20];

            //ReadSegmentDefinitions();
        }
        #endregion

        #region Action Functions
        public void Draw(SpriteBatch sb, Texture2D[] t2dMapsTex, Vector2 scroll)
        {
            Rectangle sRect = new Rectangle();
            Rectangle dRect = new Rectangle();

            sb.Begin(SpriteBlendMode.AlphaBlend);

            for (int l = 0; l < 3; l++)
            {
                float scale = 1.0f;
                Color color = Color.White;
                if (l == 0)
                {
                    color = Color.Gray;
                    scale = 0.75f;
                }
                else if (l == 2)
                {
                    color = Color.DarkGray;
                    scale = 1.25f;
                }

                scale *= 0.5f;

                for (int i = 0; i < 64; i++)
                {
                    if (mapSeg[l, i] != null)
                    {
                        sRect = segDef[mapSeg[l, i].Index].SourceRect;
                        dRect.X = (int)(mapSeg[l, i].location.X - scroll.X * scale);
                        dRect.Y = (int)(mapSeg[l, i].location.Y - scroll.Y * scale);
                        dRect.Width = (int)(sRect.Width * scale);
                        dRect.Height = (int)(sRect.Height * scale);

                        sb.Draw(t2dMapsTex[segDef[mapSeg[l, i].Index].SourceIndex],
                            dRect, sRect, color);
                    }
                }
            }
            sb.End();
        }

        public void Write()
        {
            BinaryWriter file = new BinaryWriter(File.Open(path, FileMode.OpenOrCreate, FileAccess.Write));

            for (int i = 0; i < ledge.Length; i++)
            {
                file.Write(ledge[i].totalNodes);
                for (int n = 0; n < ledge[i].totalNodes; n++)
                {
                    file.Write(ledge[i].Nodes[n].X);
                    file.Write(ledge[i].Nodes[n].Y);
                }
                file.Write(ledge[i].flags);
            }
            for (int l = 0; l < 3; l++)
            {
                for (int i = 0; i < 64; i++)
                {
                    if (mapSeg[l, i] == null)
                        file.Write(-1);
                    else
                    {
                        file.Write(mapSeg[l, i].Index);
                        file.Write(mapSeg[l, i].location.X);
                        file.Write(mapSeg[l, i].location.Y);
                    }
                }
            }
            for (int x = 0; x < 20; x++)
            {
                for (int y = 0; y < 20; y++)
                {
                    file.Write(col[x, y]);
                }
            }

            for (int i = 0; i < scripts.Length; i++)
                file.Write(scripts[i]);
            file.Close();
        }

        public void Read()
        {
            BinaryReader file = new BinaryReader(File.Open(path, FileMode.Open));

            for (int i = 0; i < ledge.Length; i++)
            {
                ledge[i] = new Ledge();
                ledge[i].totalNodes = file.ReadInt32();
                for (int n = 0; n < ledge[i].totalNodes; n++)
                {
                    ledge[i].Nodes[n] = new Vector2(file.ReadSingle(), file.ReadSingle());
                }
                ledge[i].flags = file.ReadInt32();
            }
            for (int l = 0; l < 3; l++)
            {
                for (int i = 0; i < 64; i++)
                {
                    int t = file.ReadInt32();
                    if (t == -1)
                        mapSeg[l, i] = null;
                    else
                    {
                        mapSeg[l, i] = new MapSegment();
                        mapSeg[l, i].Index = t;
                        mapSeg[l, i].location = new Vector2(file.ReadSingle(), file.ReadSingle());
                    }
                }
            }
            for (int x = 0; x < 20; x++)
            {
                for (int y = 0; y < 20; y++)
                {
                    col[x, y] = file.ReadInt32();
                }
            }

            for (int i = 0; i < scripts.Length; i++)
                scripts[i] = file.ReadString();

            file.Close();
        }
        #endregion

        #region Helper Functions
        private void ReadSegmentDefinitions()
        {
            OpenFileDialog fileDialog = new OpenFileDialog();

            // Default to the directory which contains our content files.
            string assemblyLocation = Assembly.GetExecutingAssembly().Location;
            string relativePath = System.IO.Path.Combine(assemblyLocation, "../../../../data");
            string contentPath = System.IO.Path.GetFullPath(relativePath);

            fileDialog.InitialDirectory = contentPath;

            fileDialog.Title = "Load Map Pieces Data";

            fileDialog.Filter = "All Files (*.*)|*.*";

            if (fileDialog.ShowDialog()==DialogResult.OK)
            {
                StreamReader s = new StreamReader(fileDialog.FileName);

                string t = "";
                int n;
                int currentTex = 0;
                int curDef = -1;
                Rectangle tRect = new Rectangle();
                string[] split;

                t = s.ReadLine();

                while (!s.EndOfStream)
                {
                    t = s.ReadLine();
                    if (t.StartsWith("#"))
                    {
                        if (t.StartsWith("#src"))
                        {
                            split = t.Split(' ');
                            if (split.Length > 1)
                            {
                                n = Convert.ToInt32(split[1]);
                                currentTex = n - 1;
                            }
                        }
                    }
                    else
                    {
                        if (!t.StartsWith("#model"))
                        {
                            curDef++;
                            string name = t;

                            t = s.ReadLine();
                            split = t.Split(' ');
                            if (split.Length > 3)
                            {
                                tRect.X = Convert.ToInt32(split[0]);
                                tRect.Y = Convert.ToInt32(split[1]);
                                tRect.Width = Convert.ToInt32(split[2]) - tRect.X;
                                tRect.Height = Convert.ToInt32(split[3]) - tRect.Y;
                            }
                            else
                                Console.WriteLine("read fail: " + name);

                            int tex = currentTex;

                            t = s.ReadLine();
                            int flags = Convert.ToInt32(t);

                            segDef[curDef] = new SegmentDefinition(name, tex, tRect, flags);
                        }
                        else
                        {
                            curDef++;
                            string name = t;

                            t = s.ReadLine();
                            split = t.Split(' ');
                            if (split.Length > 3)
                            {
                                tRect.X = Convert.ToInt32(split[0]);
                                tRect.Y = Convert.ToInt32(split[1]);
                                tRect.Width = Convert.ToInt32(split[2]);
                                tRect.Height = Convert.ToInt32(split[3]);
                            }
                            else
                                Console.WriteLine("read fail: " + name);

                            int tex = currentTex;

                            t = s.ReadLine();
                            int flags = Convert.ToInt32(t);

                            segDef[curDef] = new SegmentDefinition(name, tex, tRect, flags);
                        }
                    }
                }
            }
        }

        public int AddSeg(int layer, int index)
        {
            for (int i = 0; i < 64; i++)
            {
                if (mapSeg[layer, i] == null)
                {
                    mapSeg[layer, i] = new MapSegment();
                    mapSeg[layer, i].Index = index;
                    return i;
                }
            }
            return -1;
        }

        public int GetHoveredSegments(int x, int y, int l, Vector2 scroll)
        {
            float scale = 1.0f;
            if (l == 0)
                scale = 0.75f;
            else if (l == 2)
                scale = 1.25f;
            scale *= 0.5f;

            for (int i = 63; i >= 0; i--)
            {
                if (mapSeg[l, i] != null)
                {
                    Rectangle sRect = segDef[mapSeg[l, i].Index].SourceRect;
                    Rectangle dRect = new Rectangle(
                        (int)(mapSeg[l, i].location.X - scroll.X * scale),
                        (int)(mapSeg[l, i].location.Y - scroll.Y * scale),
                        (int)(sRect.Width * scale), (int)(sRect.Height * scale));
                    if (dRect.Contains(x, y))
                        return i;
                }
            }

            return -1;
        }

        public void SwapSegs(int l, int i, int n)
        {
            MapSegment tSeg = new MapSegment();

            if (mapSeg[l, i] != null && mapSeg[l, n] != null)
            {
                tSeg.Index = mapSeg[l, i].Index;
                tSeg.location = mapSeg[l, i].location;

                //tSeg.SetDefIdx(mapSeg[l, i].GetDefIdx());
                //tSeg.SetLoc(mapSeg[l, i].GetLoc());

                mapSeg[l, i].Index = mapSeg[l, n].Index;
                mapSeg[l, i].location = mapSeg[l, n].location;

                mapSeg[l, n].Index = tSeg.Index;
                mapSeg[l, n].location = tSeg.location;
            }

        }
        #endregion
    }
}